package com.sunducation.wts.navigation

import android.content.res.Resources
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.*
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.navigation.NavigationView

//navigation根节点中有个startDestination字段，他表示的是默认展示的是哪一个页面
//ragment中配置了子节点 action 。action表示的就是具体要路由的行为。
// 同样id也是其唯一标识，destination表示的是目的地，即需要路由到具体的某一个页面。popUpTo表示弹出到某一个页面
//name为固定写法，必须指明为
//androidx.navigation.fragment.NavHostFragment
/*
defaultNavHost字段表示是否拦截返回按键操作
若为true，需要的Activity中重写onSupportNavigateUp方法。 因为默认情况下返回键是不会回退fragment页面的。
override fun onSupportNavigateUp(): Boolean {
        return findNavController(R.id.nav_host_fragment).navigateUp()
    }
navGraph字段即为我们配置的navigation导航视图。
*/
 /*
 * fragment之间传递参数有两种方式：

传统的Bundle方式
通过谷歌提供的safeArgs

 * */

/*
* 总体来说Navigation的使用并不复杂，它让我们单Activity架构成为可能，无需关心具体的fragment的跳转逻辑。
* 但是同样也是有问题的，通过源码分析我们知道 在NavHostFragment的onCreateView中是创建了FrameLayout，
* 也就是说其实真正的容器是FrameLayout。在创建FragmentNavigator的时候内部使用的是replace这个API，而不是show和hide。
* 这就会导致fragment每次生命周期都会重新执行。所以和ViewModel结合使用效果应该更好。
* */

/*
* 除了做APP引导页面以外.也可以使用在App主页分tab的情况.. 甚至可以一个功能模块就一个activity大部分页面UI都使用fragment来实现,而navigation就成了管理fragment至关重要的架构.

　　但是,它不单单只能管理fragment也可以管理activity.这点你格外注意.
* */

/*
* 在<navigation里的属性:
1.android:id="@+id/demo_nav" 这个属性是你这个xml文件navigation的id,很重要,我们需要在activity的xml布局里引用,记得写上不要忘记

2.app:startDestination="@id/one" 这个属性是你首次加载的第一个页面,很重要,一般就是第一个fragment

在<fragment 里的属性:
其实就是一个节点你也可以理解成一个fragment

1.android:id="@+id/one"  每一个fragment节点都需要有自己的id,很重要. 我们需要在后面的节点上使用这些id指定跳转目标

2.android:name="demo.yt.com.demo.fragment.BlankFragment"   这个属性是你这个节点所对应的fragment(需要你导入指定的fragment文件路径),这个很重要

3.android:label="BlankFragment" 一个标签名称,用于记录这个节点的标签信息(大概可能是在代码里的Intent里获取来知晓此次是那个fragment节点在跳转,没深究了)

4.tools:layout="@layout/fragment_blank" 这个属性不是重要的,设置它后你可以在切换到Design模式后看到,视图页面的fragment的预览图(就在上面的图片里,可以直接看到fragment效果)

在<action 里的属性:
action 负责编写跳转动作

1. android:id="@+id/action_one_to_two" 这个很重要,它是这个跳转动作的id, 这个id我们将在后面的代码中调用,用于执行fragment的跳转

2. app:destination="@id/two" 跳转的目标fragment,这个很重要
* */

/*
* 让navigation与Activity关联起来
 　　现在我们已经创建了navigation,但是使用它还需要一个根Activity,它毕竟还是需要依托Activity的.

 1.创建了一个叫DemoActivity的Activity.这个没啥,下面来看这个Activity的布局xml怎么配(如下xml代码)

　　我们就关注fragment的一些属性

1.android:name="androidx.navigation.fragment.NavHostFragment"  这个非常重要,这是你告知fragment需要使用navigation模式的关键属性,另外它是固定死的.你必需写.

2. app:defaultNavHost="true"  这是你实现物理按键(比如返回键),是按一下退出一个fragment 还是直接退出这个Activity的关键属性

3.app:navGraph="@navigation/demo_nav"  很重要,这就是我们前面创建的navigation的xml文件
* */

/*
* 进入到DemoActivity后,首先会自动加载到第一个fragment. 然后我们看看如何跳转到其他fragment中

 1.从第一个碎片跳转到第二个碎片,关键代码  Navigation.findNavController(getView()).navigate(R.id.action_one_to_two);
*
* 2.从第二个碎片返回到第一个碎片,关键代码 Navigation.findNavController(getView()).popBackStack();
* */

/*
* Kotlin：

Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)
Java：

NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
* */


/*
* navigation 可以嵌套 navigation ，使用场景，一个fragment分成了两条线走，如果一条线中包含两个以上fragment，就用navigation包起来这条线
* */

/*
* 您可以使用全局操作来创建可由多个目的地共用的通用操作。例如，您可能想要不同目的地中的多个按钮导航到同一应用主屏幕。
* 在根navigation 中 加上 根 action
* */

/*
* 跳转到根navigation，尝试用一下这个findNavController().navigate(NavigationDirections.actionGlobalMainFragment)
* */

/*
* enterAnim: 跳转时的目标页面动画
exitAnim: 跳转时的原页面动画
popEnterAnim: 回退时的目标页面动画
popExitAnim:回退时的原页面动画
* */

/*
* 传递参数方法一，发送：
* val bundle = Bundle()
        bundle.putString("key", "from fragmentA")
        findNavController().navigate(R.id.action_fragmentA_to_fragmentB, bundle))
       接收：	val keyStr = arguments?.getString("key")

* 传递参数方法二，
* 如果参数类型支持 null 值，您可以使用 android:defaultValue="@null" 声明默认值 null
* 自定义类型要：Parcelable
* 可以传数组Array
* 发送：
* val action = fragmentADirections.actionFragmentAToFragmentB("from fragmentA")
        findNavController().navigate(action)
    接收：

    * val args: fragmentBArgs by navArgs()
	val keyStr = args.key
	*
	* 或者
	* arguments?.let {
            val value = FragmentBArgs.fromBundle(it).key
            .......
        }
* */

/*
* action有下面三个属性：
* launchSingleTop：如果栈中已经包含了指定要跳转的界面，那么只会保留一个，不指定则栈中会出现两个界面相同的Fragment数据，可以理解为类似activity的 singleTop，即栈顶复用模式
popUpTo(tag)：表示跳转到某个tag，并将tag之上的元素出栈。
popUpToInclusive：为true表示会弹出tag，false则不会

*
* popUpTo=FragmentA ，popUpToInclusive=true; 可以表示fragmentA只有一个，在fragmentA中按一次返回键就能退出
* */

//fragment标签代表一个fragment，其实这里不仅可以配置fragment，也可以配置activity


/*
* deeplink
深度链接，就是可以直接跳转到某个页面。navigation创建深度链接可以通过显示和隐式两种方式
* <deepLink
        android:id="@+id/deepLink"
        app:uri="www.deeplink.com/{id}" />
* */
class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration : AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.navigation_activity)

        val toolbar = findViewById<Toolbar>(R.id.toolbar)
        setSupportActionBar(toolbar)

        val host: NavHostFragment = supportFragmentManager
            .findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return

        // Set up Action Bar
        val navController = host.navController

        appBarConfiguration = AppBarConfiguration(navController.graph)

        // TODO STEP 9.5 - Create an AppBarConfiguration with the correct top-level destinations
        // You should also remove the old appBarConfiguration setup above
        val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
        appBarConfiguration = AppBarConfiguration(
                setOf(R.id.home_dest, R.id.deeplink_dest),
                drawerLayout)
        // TODO END STEP 9.5

        setupActionBar(navController, appBarConfiguration)

        setupNavigationMenu(navController)

        setupBottomNavMenu(navController)

        navController.addOnDestinationChangedListener { _, destination, _ ->
            val dest: String = try {
                resources.getResourceName(destination.id)
            } catch (e: Resources.NotFoundException) {
                Integer.toString(destination.id)
            }

            Toast.makeText(this@MainActivity, "Navigated to $dest",
                Toast.LENGTH_SHORT).show()
            Log.d("NavigationActivity", "Navigated to $dest")
        }
    }

    private fun setupBottomNavMenu(navController: NavController) {
        // TODO STEP 9.3 - Use NavigationUI to set up Bottom Nav
        //val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
        //bottomNav?.setupWithNavController(navController)
        // TODO END STEP 9.3
    }

    private fun setupNavigationMenu(navController: NavController) {
        // TODO STEP 9.4 - Use NavigationUI to set up a Navigation View
//        // In split screen mode, you can drag this view out from the left
//        // This does NOT modify the actionbar
        val sideNavView = findViewById<NavigationView>(R.id.nav_view)
        sideNavView?.setupWithNavController(navController)
        // TODO END STEP 9.4
    }

    private fun setupActionBar(navController: NavController,
                               appBarConfig : AppBarConfiguration) {
        // TODO STEP 9.6 - Have NavigationUI handle what your ActionBar displays
//        // This allows NavigationUI to decide what label to show in the action bar
//        // By using appBarConfig, it will also determine whether to
//        // show the up arrow or drawer menu icon
        setupActionBarWithNavController(navController, appBarConfig)
        // TODO END STEP 9.6
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        val retValue = super.onCreateOptionsMenu(menu)
        val navigationView = findViewById<NavigationView>(R.id.nav_view)
        // The NavigationView already has these same navigation items, so we only add
        // navigation items to the menu here if there isn't a NavigationView
        if (navigationView == null) {
            menuInflater.inflate(R.menu.overflow_menu, menu)
            return true
        }
        return retValue
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return super.onOptionsItemSelected(item)
        // TODO STEP 9.2 - Have Navigation UI Handle the item selection - make sure to delete
        //  the old return statement above
//        // Have the NavigationUI look for an action or destination matching the menu
//        // item id and navigate there if found.
//        // Otherwise, bubble up to the parent.
        return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
                || super.onOptionsItemSelected(item)
        // TODO END STEP 9.2
    }

    // TODO STEP 9.7 - Have NavigationUI handle up behavior in the ActionBar
    override fun onSupportNavigateUp(): Boolean {
//        // Allows NavigationUI to support proper up navigation or the drawer layout
//        // drawer menu, depending on the situation
        return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
    }
    // TODO END STEP 9.7
}
